{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Functions in Symata"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "$(\"div.input_prompt\").css({\"color\": \"blue\"})"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "using Symata # load Symata and enter Symata mode"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are (more or less) three ways to define functions in Symata.\n",
    "* via rules\n",
    "* via the host language (Julia)\n",
    "* via the pure function expression head `Function`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basics of defining and using functions\n",
    "\n",
    "This is how you define a function using rules"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ 4 $$"
      ],
      "text/plain": [
       "L\"$$ 4 $$\""
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f(x_) := x^2\n",
    "\n",
    "f(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note the trailing underscore in `x_`.  This function is implemented via a *rule* for rewriting expressions.\n",
    "\n",
    "The argument to `f` can be any expression:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$  \\left[  \\left( x + y \\right) ^{2},\\text{\"dog\"}^{2},4.0 \\right]  $$"
      ],
      "text/plain": [
       "L\"$$  \\left[  \\left( x + y \\right) ^{2},\\text{\\\"dog\\\"}^{2},4.0 \\right]  $$\""
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[f(x+y), f(\"dog\"), f(2.0)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "ClearAll(f)   # remove the definition for `f`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This computes the `n`th Fibonacci number."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ 55 $$"
      ],
      "text/plain": [
       "L\"$$ 55 $$\""
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib(1) := 1\n",
    "fib(2) := 1\n",
    "fib(n_) := fib(n-1) + fib(n-2)\n",
    "\n",
    "fib(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A compound statement can be written like this."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ 1 + y $$"
      ],
      "text/plain": [
       "L\"$$ 1 + y $$\""
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "addone(x_) := (a = 1,  x + a)\n",
    "\n",
    "addone(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "But, the variable `a` is not local to the function. The global value of a is set."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ 1 $$"
      ],
      "text/plain": [
       "L\"$$ 1 $$\""
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To make variables local to a function, use `Module`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "g(x_) := Module([c,d],(c=1,d=3,a+d+x))    # local variables are lexically scoped."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ 4 + z $$"
      ],
      "text/plain": [
       "L\"$$ 4 + z $$\""
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g(z)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The global values of `c` and `d` are not affected."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$  \\left[ c,d \\right]  $$"
      ],
      "text/plain": [
       "L\"$$  \\left[ c,d \\right]  $$\""
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[c,d]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The argument to the function `f` in `In(2)` can be any expression. You can also make multiple definitions that apply only when the argument satisfies some requirements. For example, the following makes a definition for `g` that only applies for floating point arguments greater than `5`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "gt5(x_) := x > 5\n",
    "\n",
    "g(x_Float:?(gt5)) := 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ 1 $$"
      ],
      "text/plain": [
       "L\"$$ 1 $$\""
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g(10.0)   # The conditions in the new definition are satisfied by 10.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$  \\left[ 8.0,14,4 + q + r \\right]  $$"
      ],
      "text/plain": [
       "L\"$$  \\left[ 8.0,14,4 + q + r \\right]  $$\""
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[g(4.0), g(10), g(q + r)] # The definition in In(13) applies here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can do structural matching on the argument. This matches anything that has the form of a square."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "h(x_^2) := x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$  \\left[ r,h \\!  \\left( r^{3} \\right) ,q + r,h \\!  \\left( q^{2} + 2 \\ q \\ r + r^{2} \\right) ,4,2 \\right]  $$"
      ],
      "text/plain": [
       "L\"$$  \\left[ r,h \\!  \\left( r^{3} \\right) ,q + r,h \\!  \\left( q^{2} + 2 \\ q \\ r + r^{2} \\right) ,4,2 \\right]  $$\""
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[h(r^2), h(r^3), h((r+q)^2), h(Expand((r+q)^2)), 4 , 2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Although `4` is the square of `2`, `2` is the square of `Sqrt(2)`, and `q^2 +2*q*r + r^2` is the square of `r+q`, none of these match. Only expressions of the form `Power(expr,2)` match. We see why `h(r^2)` matches by looking at the full form of `r^2`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Power(r,2)"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "FullForm(r^2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "ClearAll(f,h,a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Use two trailing underscores to match one or more elements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "g(x_Symbol, p__Integer) := Apply(Plus, x^[p])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ y + y^{4} + y^{7} + y^{10} $$"
      ],
      "text/plain": [
       "L\"$$ y + y^{4} + y^{7} + y^{10} $$\""
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g(y,1,4,7,10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "Apply(ClearAll, UserSyms())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set and SetDelayed\n",
    "\n",
    "Why did we use `:=` rather than `=` above ?  One reason is that it is safer. The following example shows why."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$  \\left[ a^{2},a^{2},9,a^{2} \\right]  $$"
      ],
      "text/plain": [
       "L\"$$  \\left[ a^{2},a^{2},9,a^{2} \\right]  $$\""
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f(x_) := x^2\n",
    "g(x_) = x^2\n",
    "x = 3\n",
    "h(x_) = x^2\n",
    "j(x_) := x^2\n",
    "\n",
    "[f(a), g(a), h(a), j(a)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the definition of `h`, `x` is not a dummy variable. If you are beginning with Symata it is enough to know that `:=` should be preferred and you can skip the following.\n",
    "\n",
    "What does `f(x_) := x^2` do ? When Symata evaluates this expression, it does not evaluate the right hand side, but rather holds it in its unevaluated form. When the rule is applied, say by evaluating `f(a+b)`, the value that matches `x_`, in this case `a+b`, is substituted for `x` in the right hand side and the result is evaluated with the result `(a+b)^2`. Note that the value of `x` at the time the definition is first evaluated has no affect on this result: The right hand side is never evaluated before subsituting for `x`.\n",
    "\n",
    "The definition `g(x_) = x^2` differs in that the right hand side is evaluated when the definition is made. After this, everything is the same as for `:=`. The value that matches `x_` is substituted in the right hand side and the result is evaluated. If `x` was unbound when the definition was made, the results are identical, because the substituion will be made before evaluating the right hand side again, so assignments to `x` in the mean time will have no effect. However if `x` *is* bound at the time of the definition, then the value of `x^2` at the time of defnition is stored and the match of `x_` is substituted into this expression. If `x` had a value of `3`, then `a+b` is substituted into `3`, which just results in `3`. \n",
    "\n",
    "These \"function\" definitions actually define `DownValues`. We can see that the definitions of `f`,`g`, and `j` are the same, no matter what the future values of `x`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$  \\left[  \\left[ \\text{HoldPattern} \\!  \\left( f \\!  \\left( x\\text{_} \\right)  \\right) \\text{:>}x^{2} \\right] , \\left[ \\text{HoldPattern} \\!  \\left( g \\!  \\left( x\\text{_} \\right)  \\right) \\text{:>}x^{2} \\right] , \\left[ \\text{HoldPattern} \\!  \\left( h \\!  \\left( x\\text{_} \\right)  \\right) \\text{:>}9 \\right] , \\left[ \\text{HoldPattern} \\!  \\left( j \\!  \\left( x\\text{_} \\right)  \\right) \\text{:>}x^{2} \\right]  \\right]  $$"
      ],
      "text/plain": [
       "L\"$$  \\left[  \\left[ \\text{HoldPattern} \\!  \\left( f \\!  \\left( x\\text{_} \\right)  \\right) \\text{:>}x^{2} \\right] , \\left[ \\text{HoldPattern} \\!  \\left( g \\!  \\left( x\\text{_} \\right)  \\right) \\text{:>}x^{2} \\right] , \\left[ \\text{HoldPattern} \\!  \\left( h \\!  \\left( x\\text{_} \\right)  \\right) \\text{:>}9 \\right] , \\left[ \\text{HoldPattern} \\!  \\left( j \\!  \\left( x\\text{_} \\right)  \\right) \\text{:>}x^{2} \\right]  \\right]  $$\""
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Map(DownValues, [f,g,h,j])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "ClearAll(f,g,h,j,x)  # clear the symbols used in this example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Julia functions\n",
    "\n",
    "We mentioned above that these defintions define `Rule`s. You can also use compiled functions in Symata. One way is to code such a function directly in the host language, Julia."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "1;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "ClearAll(g,h,a,b)\n",
    "#  J(expr) interprets expr as Julia code\n",
    "f = J((x) -> x^2 ) ;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ 9 $$"
      ],
      "text/plain": [
       "L\"$$ 9 $$\""
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ \\text{\"dogdog\"} $$"
      ],
      "text/plain": [
       "L\"$$ \\text{\\\"dogdog\\\"} $$\""
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f(\"dog\")  # This calls the Julia function, so we get what \"dog\"^2 means in Julia"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that we did not use `:=` in the definition of `f`. That is, `f := :((x) -> x^2 )`. This would create a new anonymous function everytime `f` is called, which would be very slow."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$  \\left( a + b \\right) ^{2} $$"
      ],
      "text/plain": [
       "L\"$$  \\left( a + b \\right) ^{2} $$\""
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f(a+b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The last example works because `^` has been overloaded in Julia to operate on Symata expressions. (Symata expressions are objects of type `Symata.Mxpr` in Julia.)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pure (anonymous) functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Anonymous or pure functions are used like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ a^{2} $$"
      ],
      "text/plain": [
       "L\"$$ a^{2} $$\""
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Function(x, x^2)(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The infix operator `->` is equivalent to `Function`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ a^{2} $$"
      ],
      "text/plain": [
       "L\"$$ a^{2} $$\""
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(x -> x^2)(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A function of two variables is defined like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ 25 $$"
      ],
      "text/plain": [
       "L\"$$ 25 $$\""
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "([x,y] -> x^2 + y^2)(3,4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "### Version and date"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "symata version 0.3.0-dev.7\n",
      "julia version  0.6.0-dev.435\n",
      "python version 2.7.12\n",
      "sympy version  1.0\n"
     ]
    }
   ],
   "source": [
    "VersionInfo()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$ 2016-11-28T22:36:18.794 $$"
      ],
      "text/plain": [
       "L\"$$ 2016-11-28T22:36:18.794 $$\""
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Now()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Julia 0.6.0-dev",
   "language": "julia",
   "name": "julia-0.6"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "0.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
